package com.typingtutor.ui.tabs;

import com.typingtutor.db.DatabaseManager;
import com.typingtutor.dto.TypingDataDAO;
import com.typingtutor.ui.TypingTutor;
import lombok.Getter;
import org.apache.commons.lang3.StringUtils;
import org.jfree.chart.*;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.axis.NumberTickUnit;
import org.jfree.chart.axis.SymbolAxis;
import org.jfree.chart.entity.ChartEntity;
import org.jfree.chart.entity.XYItemEntity;
import org.jfree.chart.labels.CrosshairLabelGenerator;
import org.jfree.chart.panel.CrosshairOverlay;
import org.jfree.chart.plot.Crosshair;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Rectangle2D;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.*;
import java.util.List;

public class StatisticsChartTab extends JPanel {

    @Getter
    private JPanel panel;
    private TypingTutor mainFrame;
    private CustomChartPanel chartPanel;
    // 在 StatisticsChartTab 类中添加以下方法
    @Getter
    private JComboBox<String> dateComboBox;

    // 使用 XY 折线图的数据集与系列
    private XYSeriesCollection dataset;
    private XYSeries seriesCorrect;
    private XYSeries seriesError;

    // 辅助线（交叉线）对象
    private Crosshair domainCrosshair;
    private Crosshair rangeCrosshair;

    // 用于存储当前 X 轴（类别）标签列表，便于根据 x 值索引获取名称
    private List<String> currentCategories;

    public StatisticsChartTab(TypingTutor mainFrame) {
        this.mainFrame = mainFrame;
        initComponents();
        loadDataFromDatabase();
    }

    /**
     * 创建 XY 折线图（后续使用 SymbolAxis 显示类别标签）
     */
    private JFreeChart createChart() {
        // 初始化数据系列
        dataset = new XYSeriesCollection();
        seriesCorrect = new XYSeries("正确次数");
        seriesError = new XYSeries("错误次数");
        dataset.addSeries(seriesCorrect);
        dataset.addSeries(seriesError);

        // 创建 XY 折线图，默认 X 轴为 NumberAxis（后续用 SymbolAxis 替换）
        JFreeChart chart = ChartFactory.createXYLineChart(
                "打字正确与错误次数统计",  // 图表标题
                "假名 - 中文含义",        // X 轴标签
                "次数",                  // Y 轴标签
                dataset,
                PlotOrientation.VERTICAL,
                true,   // 图例
                true,   // 提示工具
                false   // URL 链接
        );
        XYPlot plot = chart.getXYPlot();
        // 设置 Y 轴，确保自动包含零值
        NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
        rangeAxis.setAutoRangeIncludesZero(true);
        return chart;
    }

    private void initComponents() {
        panel = new JPanel(new BorderLayout());
        // 创建图表
        JFreeChart chart = createChart();
        chartPanel = new CustomChartPanel(chart);

        // 初始化下拉框
        dateComboBox = new JComboBox<>();
        dateComboBox.addActionListener(new DateSelectionListener());
        // 添加默认今日日期
        String today = TypingDataDAO.getInstance().getDateFormat().format(new Date());
        dateComboBox.addItem(today);
        dateComboBox.setSelectedItem(today);

        JPanel comboBoxPanel = new JPanel(new BorderLayout());
        comboBoxPanel.add(dateComboBox, BorderLayout.NORTH);
        comboBoxPanel.setOpaque(false);
        chartPanel.setLayout(new BorderLayout());
        chartPanel.add(comboBoxPanel, BorderLayout.NORTH);
        domainCrosshair = new Crosshair(Double.NaN, Color.GRAY, new BasicStroke(1f));
        domainCrosshair.setLabelVisible(true);
        domainCrosshair.setLabelFont(new Font("SansSerif", Font.PLAIN, 12));
        domainCrosshair.setLabelBackgroundPaint(new Color(255, 255, 200));
        domainCrosshair.setLabelOutlineStroke(new BasicStroke(0.5f));
        domainCrosshair.setLabelOutlinePaint(Color.GRAY);
        domainCrosshair.setLabelGenerator(new CrosshairLabelGenerator() {
            @Override
            public String generateLabel(Crosshair crosshair) {
                // 根据 crosshair.getValue() 得到对应的类别索引
                int idx = (int) Math.round(crosshair.getValue());
                if (currentCategories != null && idx >= 0 && idx < currentCategories.size()) {
                    return currentCategories.get(idx);
                }
                return "";
            }
        });


        rangeCrosshair = new Crosshair(Double.NaN, Color.GRAY, new BasicStroke(1f));
        rangeCrosshair.setLabelVisible(true);
        rangeCrosshair.setLabelFont(new Font("SansSerif", Font.PLAIN, 12));
        rangeCrosshair.setLabelBackgroundPaint(new Color(255, 255, 200));
        rangeCrosshair.setLabelOutlineStroke(new BasicStroke(0.5f));
        rangeCrosshair.setLabelOutlinePaint(Color.GRAY);

        // 添加 CrosshairOverlay，实现辅助线效果
        CrosshairOverlay crosshairOverlay = new CrosshairOverlay();
        domainCrosshair = new Crosshair(Double.NaN, Color.GRAY, new BasicStroke(1f));
        domainCrosshair.setLabelVisible(true);
        domainCrosshair.setLabelFont(new Font("SansSerif", Font.PLAIN, 12));
        domainCrosshair.setLabelBackgroundPaint(new Color(255, 255, 200));
        domainCrosshair.setLabelOutlineStroke(new BasicStroke(0.5f));
        domainCrosshair.setLabelOutlinePaint(Color.GRAY);
        domainCrosshair.setLabelGenerator(new CustomCrosshairLabelGenerator(currentCategories));

        rangeCrosshair = new Crosshair(Double.NaN, Color.GRAY, new BasicStroke(1f));
        rangeCrosshair.setLabelVisible(true);
        rangeCrosshair.setLabelFont(new Font("SansSerif", Font.PLAIN, 12));
        rangeCrosshair.setLabelBackgroundPaint(new Color(255, 255, 200));
        rangeCrosshair.setLabelOutlineStroke(new BasicStroke(0.5f));
        rangeCrosshair.setLabelOutlinePaint(Color.GRAY);

        crosshairOverlay.addDomainCrosshair(domainCrosshair);
        crosshairOverlay.addRangeCrosshair(rangeCrosshair);
        chartPanel.addOverlay(crosshairOverlay);


        chartPanel.addChartMouseListener(new ChartMouseListener() {
            @Override
            public void chartMouseClicked(ChartMouseEvent event) {
                // 根据需要处理点击事件
            }

            @Override
            public void chartMouseMoved(ChartMouseEvent event) {
                Point mousePoint = event.getTrigger().getPoint();
                ChartEntity entity = event.getEntity();
                double xVal = Double.NaN;
                double yVal = Double.NaN;
                if (entity instanceof XYItemEntity) {
                    // 如果鼠标正悬停在数据点上，则直接使用该数据点
                    XYItemEntity itemEntity = (XYItemEntity) entity;
                    int seriesIndex = itemEntity.getSeriesIndex();
                    int itemIndex = itemEntity.getItem();
                    xVal = dataset.getXValue(seriesIndex, itemIndex);
                    yVal = dataset.getYValue(seriesIndex, itemIndex);
                } else {
                    // 否则遍历所有数据点，找到离鼠标最近的点
                    ChartRenderingInfo info = chartPanel.getChartRenderingInfo();
                    Rectangle2D dataArea = info.getPlotInfo().getDataArea();
                    XYPlot plot = chartPanel.getChart().getXYPlot();
                    double minDistance = Double.MAX_VALUE;
                    for (int s = 0; s < dataset.getSeriesCount(); s++) {
                        int itemCount = dataset.getItemCount(s);
                        for (int i = 0; i < itemCount; i++) {
                            double dataX = dataset.getXValue(s, i);
                            double dataY = dataset.getYValue(s, i);
                            // 将数据值转换为图表上的 Java2D 坐标
                            double xx = plot.getDomainAxis().valueToJava2D(dataX, dataArea, plot.getDomainAxisEdge());
                            double yy = plot.getRangeAxis().valueToJava2D(dataY, dataArea, plot.getRangeAxisEdge());
                            double distance = Point.distance(mousePoint.x, mousePoint.y, xx, yy);
                            if (distance < minDistance) {
                                minDistance = distance;
                                xVal = dataX;
                                yVal = dataY;
                            }
                        }
                    }
                }
                // 更新交叉线位置为找到的数据点的 x,y 值
                if (!Double.isNaN(xVal) && !Double.isNaN(yVal)) {
                    domainCrosshair.setValue(xVal);
                    rangeCrosshair.setValue(yVal);
                    // 这里不需要调用 setLabel() 了，因为生成器自动调用 generateLabel()，返回对应的类别名称
                }
            }
        });

        chartPanel.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseExited(MouseEvent e) {
                domainCrosshair.setValue(Double.NaN);
                rangeCrosshair.setValue(Double.NaN);
                domainCrosshair.setLabelVisible(false);
                rangeCrosshair.setLabelVisible(false);
            }

            @Override
            public void mouseEntered(MouseEvent e) {
                domainCrosshair.setLabelVisible(true);
                rangeCrosshair.setLabelVisible(true);
            }
        });

        // 添加鼠标监听，鼠标移出图表时隐藏辅助线
        chartPanel.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseExited(MouseEvent e) {
                domainCrosshair.setValue(Double.NaN);
                rangeCrosshair.setValue(Double.NaN);
                domainCrosshair.setLabelVisible(false);
                rangeCrosshair.setLabelVisible(false);
            }

            @Override
            public void mouseEntered(MouseEvent e) {
                domainCrosshair.setLabelVisible(true);
                rangeCrosshair.setLabelVisible(true);
            }
        });

        panel.add(chartPanel, BorderLayout.CENTER);
    }

    /**
     * 将统计数据转换为 XYSeries 数据，更新图表及 X 轴标签（使用 SymbolAxis 显示类别名称）。
     */
    private void updateDataset(String date) {
        seriesCorrect.clear();
        seriesError.clear();

        LinkedHashMap<String, Integer> correctMap = TypingDataDAO.getInstance().getCorrectCountByDate(date);
        LinkedHashMap<String, Integer> errorMap = TypingDataDAO.getInstance().getErrorCountByDate(date);

        List<String> categories = new ArrayList<>(correctMap.keySet());
        currentCategories = categories;

        // 添加数据点，将 x 值作为类别在列表中的索引
        for (int i = 0; i < categories.size(); i++) {
            String key = categories.get(i);
            int correctValue = correctMap.getOrDefault(key, 0);
            int errorValue = errorMap.getOrDefault(key, 0);
            seriesCorrect.add(i, correctValue);
            seriesError.add(i, errorValue);
        }

        // 更新 X 轴为 SymbolAxis 显示具体文本标签
        XYPlot plot = chartPanel.getChart().getXYPlot();
        String[] labels = categories.toArray(new String[0]);
        SymbolAxis domainAxis = new SymbolAxis("假名 - 中文含义", labels);
        domainAxis.setTickUnit(new NumberTickUnit(1));
        plot.setDomainAxis(domainAxis);

        // 设置自定义标签生成器，让辅助线显示类别名称
        if (domainCrosshair != null) {
            domainCrosshair.setLabelGenerator(new CustomCrosshairLabelGenerator(currentCategories));
        }

        // 动态调整 Y 轴范围
        NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
        double max = getMaxCount();
        rangeAxis.setRange(0, max < 10 ? 10 : max + 5);

        chartPanel.repaint();
    }


    /**
     * 遍历数据集计算最大值，用于动态设置 Y 轴范围
     */
    private double getMaxCount() {
        double max = 0;
        for (int s = 0; s < dataset.getSeriesCount(); s++) {
            for (int i = 0; i < dataset.getItemCount(s); i++) {
                double value = dataset.getYValue(s, i);
                if (value > max) {
                    max = value;
                }
            }
        }
        return max;
    }

    private static class CustomCrosshairLabelGenerator implements CrosshairLabelGenerator {
        private List<String> categories;

        public CustomCrosshairLabelGenerator(List<String> categories) {
            this.categories = categories;
        }

        @Override
        public String generateLabel(Crosshair crosshair) {
            int idx = (int) Math.round(crosshair.getValue());
            if (categories != null && idx >= 0 && idx < categories.size()) {
                return categories.get(idx);
            }
            return "";
        }
    }


    private class DateSelectionListener implements ActionListener {
        @Override
        public void actionPerformed(ActionEvent e) {
            String selectedDate = (String) dateComboBox.getSelectedItem();
            if (selectedDate != null) {
                updateDataset(selectedDate);
            }
        }
    }

    /**
     * 自定义 ChartPanel，如有需要可进一步扩展
     */
    private static class CustomChartPanel extends ChartPanel {
        public CustomChartPanel(JFreeChart chart) {
            super(chart);
        }
    }

    /**
     * 从 H2 数据库加载数据，更新统计计算器，并确保下拉框包含所有日期，
     * 数据加载完成后根据选中日期更新图表数据
     */
    public void loadDataFromDatabase() {
        clearData();
        Connection connection = null;
        try {
            connection = DatabaseManager.getConnection();
            connection.setAutoCommit(false);
            Statement stmt = connection.createStatement();
            ResultSet rs = stmt.executeQuery("SELECT `date`, display_name, correct_count, error_count, create_time " +
                    "FROM typing_data ORDER BY create_time ASC");

            while (rs.next()) {
                String date = rs.getString("date");
                String kanaMeaning = rs.getString("display_name");
                int correctCount = rs.getInt("correct_count");
                int errorCount = rs.getInt("error_count");

                // 使用统计计算器保存数据，直接传入正确和错误次数
                TypingDataDAO.getInstance().updateStatistics(kanaMeaning, date, correctCount, errorCount);

                // 确保下拉框包含该日期
                boolean exists = false;
                ComboBoxModel<String> model = dateComboBox.getModel();
                for (int i = 0; i < model.getSize(); i++) {
                    if (model.getElementAt(i).equals(date)) {
                        exists = true;
                        break;
                    }
                }
                if (!exists) {
                    dateComboBox.addItem(date);
                }
            }
            // 数据加载完毕后，取当前选中日期更新图表
            String selectedDate = (String) dateComboBox.getSelectedItem();
            if (selectedDate != null && StringUtils.isNoneBlank(selectedDate)) {
                updateDataset(selectedDate);
            }
            connection.commit();
        } catch (Exception e) {
            // 回滚事务
            if (connection != null) {
                try {
                    connection.rollback();
                    System.out.println("事务回滚！");
                } catch (SQLException ex) {
                    ex.printStackTrace();
                }
            }
            e.printStackTrace();
        } finally {
            // 关闭连接
            try {
                if (connection != null) connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 清空下拉框与数据集，并刷新图表显示
     */
    public void clearData() {
        dateComboBox.removeAllItems();
        seriesCorrect.clear();
        seriesError.clear();
        chartPanel.repaint();
    }

}
